package service

import (
	"context"
	"errors"
	"fmt"
	"github.com/vmihailenco/msgpack/v5"
	"go.uber.org/zap"
	"gogogo-server/gameserver/global"
	"gorm.io/gorm"
)

type Identifiable interface {
	GetID() uint
}

// GenericService 是一个泛型服务，用于处理任何类型的模型
type GenericService[T Identifiable] struct{}

func NewGenericService[T Identifiable]() *GenericService[T] {
	return &GenericService[T]{}
}

func (s *GenericService[Player]) GetByName(name string) (*Player, error) {
	var player Player
	result := global.GGG_DB.Where("name = ?", name).First(&player)
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			// 玩家不存在
			return nil, result.Error
		}
		// 数据库错误
		return nil, result.Error
	}
	return &player, nil
}

func (s *GenericService[T]) GetByID(id uint) (*T, error) {
	ctx := context.Background()
	var entity T

	// 尝试从 Redis 获取数据
	key := fmt.Sprintf("entity:%d", id)
	cachedVal, err := global.GGG_Rdb.Get(ctx, key).Result()
	if err == nil {
		err = msgpack.Unmarshal([]byte(cachedVal), &entity)
		if err != nil {
			return nil, err
		}
		return &entity, nil
	}

	// 缓存未命中，从数据库获取
	if result := global.GGG_DB.First(&entity, id); result.Error != nil {
		return nil, result.Error
	}

	// 序列化 entity 并存储到 Redis
	serializedEntity, err := msgpack.Marshal(entity)
	if err != nil {
		return nil, err
	}
	global.GGG_Rdb.Set(ctx, key, serializedEntity, 0)

	return &entity, nil
}

func (s *GenericService[T]) Save(entity *T) error {
	ctx := context.Background()

	// 保存到 MySQL
	if err := global.GGG_DB.Save(entity).Error; err != nil {
		zap.S().Error("Error saving to DB: %v", err)
		return err
	}

	// 序列化 entity 并更新 Redis 缓存
	serializedEntity, err := msgpack.Marshal(entity)
	if err != nil {
		return err
	}
	key := fmt.Sprintf("entity:%d", getEntityID(entity)) // 假设 T 类型有获取 ID 的方法
	global.GGG_Rdb.Set(ctx, key, serializedEntity, 0)

	return nil
}

func (s *GenericService[T]) Create(entity *T) error {
	ctx := context.Background()

	// 向 MySQL 添加新实体
	if err := global.GGG_DB.Create(entity).Error; err != nil {
		return err
	}

	// 序列化 entity 并存储到 Redis
	serializedEntity, err := msgpack.Marshal(entity)
	if err != nil {
		return err
	}
	key := fmt.Sprintf("entity:%d", getEntityID(entity)) // 假设 T 类型有获取 ID 的方法
	global.GGG_Rdb.Set(ctx, key, serializedEntity, 0)

	return nil
}

// getEntityID 需要为泛型实体定义一个获取 ID 的方法
func getEntityID[T Identifiable](entity *T) uint {
	return (*entity).GetID()
}

func (s *GenericService[T]) ExistsByID(id uint) (bool, error) {
	ctx := context.Background()
	var entity T

	// 尝试从数据库获取指定 ID 的实体
	result := global.GGG_DB.WithContext(ctx).First(&entity, id)
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			// 没有找到记录，ID 不存在
			return false, nil
		}
		// 发生了其他错误
		return false, result.Error
	}

	// 找到了记录，ID 存在
	return true, nil
}
